package com.hoyue.system.realm;

import com.hoyue.common.utils.ShiroSessionUtils;
import com.hoyue.common.utils.ShiroUtils;
import com.hoyue.system.bean.Role;
import com.hoyue.system.bean.User;
import com.hoyue.system.service.PermissionService;
import com.hoyue.system.service.RoleService;
import com.hoyue.system.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;
import java.util.Set;


/**
 * @author 空白
 * @version 1.0
 * Create by 2019/08/08 01:49
 */
public class UserRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    @Resource
    private PermissionService permissionService;

    /**
     * 授权（为当前登录用户授予权限及角色）
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //从principalCollection中获取登录用户信息
        String email = (String)principals.getPrimaryPrincipal();
        //授权对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        try {
            // 查询当前用户拥有的角色
            Set<Role> roles = ShiroUtils.getRoles();
            if (roles == null) {
                Integer userId = ShiroUtils.getUserId();
                if (userId == null) {
                    userId = userService.getUserByEmail(email).getId();
                }
                // 从数据库中取出角色
                roles = roleService.getRoles(userId);
                ShiroSessionUtils.setShiroAttribute("roles", roles);
            }
            // 查询当前角色拥有的权限
            Set<String> permissions = ShiroUtils.getPermissions();
            // 若当前用户没有权限
            if (permissions == null) {
                for (Role role : roles) {
                    // 获取到的角色放进去
                    authorizationInfo.addRole(role.getRoleName());
                    System.out.println(authorizationInfo.getRoles());
                    // 查询权限
                    permissions = permissionService.getPermission(role.getId());
                }
                ShiroSessionUtils.setShiroAttribute("roleName", authorizationInfo.getRoles());
                ShiroSessionUtils.setShiroAttribute("permissions", permissions);
            }
            authorizationInfo.setRoles((Set<String>)ShiroSessionUtils.getShiroAttribute("roleName"));
            // 把获取到的权限放进shiro会话中
            authorizationInfo.setStringPermissions(permissions);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return authorizationInfo;
    }

    /**
     * 登录认证器
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//        将AuthenticationToken 转换为 UsernamePasswordToken 类型
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
//        从UsernamePasswordToken中获取userEmail
        String email = upToken.getPrincipal().toString();
        try {
            User user = userService.getUserByEmail(email);
            if (user != null) {
                ShiroSessionUtils.setShiroAttribute("user", user);
                //获取密码
                String password = user.getPassword();
                //获取盐值，并在盐值后面加上用户email
                String salt = user.getSalt();

                //构造AuthenticationInfo对象，通常使用实现类SimpleAuthenticationInfo
                //第一个参数：认证信息。这里是使用了用户email
                //第二个参数：数据表中获取的密码
                //第三个参数：经过二次加上email的盐值
                //第四个参数：当前realm对象的name，调用父类的getName()方法即可
                SimpleAuthenticationInfo authenticationInfo =
                        new SimpleAuthenticationInfo(email,password, ByteSource.Util.bytes(salt+email),getName());
                return authenticationInfo;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
